/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-12-20
 * Time: 04:09
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;

namespace patterns
{
	/// <summary>
	/// Observes an instance of SubjectForObservation having the same base state class
	/// as template argument as this instance
	/// 
	/// Implements the Observer design pattern
	/// </summary>
	public abstract class Observer<StateType>
	{
		#region members
		
		/// <summary>
		/// The current state of the observed subject
		/// </summary>
		protected StateType								m_SubjectsState;
		/// <summary>
		/// The subject to observ
		/// </summary>
		private SubjectForObservation<StateType>		m_Subject;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Default constructor, initializes members, sets the subject to null
		/// </summary>
		protected Observer()
		{
			m_SubjectsState = default(StateType);
			m_Subject = null;
		}
		
		/// <summary>
		/// Constructor, initializes members, subscribes to the subject
		/// </summary>
		/// <param name="subject">The instance of SubjectForObservation to subscribe to</param>
		protected Observer(SubjectForObservation<StateType> subject)
		{
			m_SubjectsState = default(StateType);
			m_Subject = null;
			Subscribe(subject);
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Subscribes to the subject. If this observer is allready observing a subject, this
		/// subscription will be cancelled first
		/// </summary>
		/// <param name="subject">The instance of SubjectForObservation to subscribe to</param>
		public void Subscribe(SubjectForObservation<StateType> subject)
		{
			if(m_Subject != null)
			{
				m_Subject.RemoveObserver(this);
			}
			
			m_Subject = subject;
			m_Subject.AddObserver(this);
			UpdateObserver();
		}
		
		/// <summary>
		/// If this observer is subscribing to a subject, this subscription will be cancelled
		/// </summary>
		public void Unsubscribe()
		{
			if(m_Subject != null)
			{
				m_Subject.RemoveObserver(this);
				m_Subject = null;
			}
		}
		
		#endregion
		
		#region virtuals
		
		/// <summary>
		/// Called by the subject to notify the observer about the need for updating
		/// the state from the subject. Override this to implement further functionality.
		/// Remeber though, to call base() first thing in that method.
		/// 
		/// The syntax for the override declaration (outside this assembly) is
		/// <code>protected override void UpdateObserver()</code>
		/// </summary>
		protected internal virtual void UpdateObserver()
		{
			if(m_Subject != null)
			{
				m_SubjectsState = m_Subject.State;
			}
		}
		
		#endregion
	}
}
